#pragma once;
#include "vec3.h"
#include "GlobalDefine.h"

namespace mray{
	struct Result;
	struct BaseTexture;
	struct BaseSampler;

	struct BaseMaterial{
		//shade is about brdf
		BaseMaterial():m_pTex(nullptr), m_color(WHITE), m_dblSides(false){}
		BaseMaterial(const vec3& color):m_pTex(nullptr), m_color(color){}
		BaseMaterial(BaseTexture* pTexture):m_pTex(pTexture), m_color(WHITE){}
		virtual ~BaseMaterial(){}

		//wi       from collosion point to outside
		//result.d from collision point to outside
		virtual vec3 Shade(const vec3& wi, const vec3& ligColor, const Result& result)const = 0;

		//wi	in direction
		//uv	the samples
		virtual float Sample(const Result& result, const vec2& uv, vec3& wi)const=0;

		void SetTex(BaseTexture* pTex){m_pTex = pTex;}
		void SetColor(const vec3& color){m_color = color;}
		vec3 GetColor(const vec2& uv)const;

	protected:
		BaseTexture*	m_pTex;
		vec3			m_color;
		bool			m_dblSides;
	};

	struct LambertMaterial : public BaseMaterial{
		LambertMaterial():BaseMaterial(){}
		LambertMaterial(const vec3& color):BaseMaterial(color){}
		LambertMaterial(BaseTexture* pTexture):BaseMaterial(pTexture){}
		virtual ~LambertMaterial(){}

		virtual vec3 Shade(const vec3& wi, const vec3& ligColor, const Result& result)const override;
		virtual float Sample(const Result& result, const vec2& uv, vec3& wi)const override;
	};

	struct EmissiveMaterial : public BaseMaterial{
		EmissiveMaterial():BaseMaterial(){}
		EmissiveMaterial(const vec3& color):BaseMaterial(color){}
		EmissiveMaterial(BaseTexture* pTexture):BaseMaterial(pTexture){}
		virtual ~EmissiveMaterial(){ }

		virtual vec3 Shade(const vec3& wi, const vec3& ligColor, const Result& result)const override;
		virtual float Sample(const Result& result, const vec2& uv, vec3& wi)const override;
	};

	struct PhongMaterial : public BaseMaterial{
		PhongMaterial():
			BaseMaterial(),m_exp(2.f),m_kd(0.6f),m_ks(0.4f){}
		PhongMaterial(const vec3& color, float exp, float kd, float ks):
			BaseMaterial(color),m_exp(exp),m_kd(kd),m_ks(ks){}
		PhongMaterial(BaseTexture* pTexture, float exp, float kd, float ks):
			BaseMaterial(pTexture),m_exp(exp),m_kd(kd),m_ks(ks){}
		virtual ~PhongMaterial(){}

		virtual vec3 Shade(const vec3& wi, const vec3& ligColor, const Result& result)const override;
		virtual float Sample(const Result& result, const vec2& uv, vec3& wi)const override;

	protected:
		float m_exp;
		float m_kd;
		float m_ks;
	};

	struct BlinnMaterial : public PhongMaterial{
		BlinnMaterial():PhongMaterial(){}
		BlinnMaterial(const vec3& color, float exp, float kd, float ks):PhongMaterial(color, exp, kd, ks){}
		BlinnMaterial(BaseTexture* pTexture, float exp, float kd, float ks):PhongMaterial(pTexture, exp, kd, ks){}

		virtual vec3 Shade(const vec3& wi, const vec3& ligColor, const Result& result)const override;
		virtual float Sample(const Result& result, const vec2& uv, vec3& wi)const override;

	};

	struct MirrorMaterial : public BaseMaterial{
		MirrorMaterial():BaseMaterial(),m_noise(0.f){}
		MirrorMaterial(const vec3& color, float noise):BaseMaterial(color), m_noise(noise){}
		MirrorMaterial(BaseTexture* pTexture, float noise):BaseMaterial(pTexture), m_noise(noise){}
		virtual ~MirrorMaterial(){}

		virtual vec3 Shade(const vec3& wi, const vec3& ligColor, const Result& result)const override;
		virtual float Sample(const Result& result, const vec2& uv, vec3& wi)const override;

	private:
		float m_noise;
	};

	struct TransparentMaterial : public BaseMaterial
	{
		TransparentMaterial():BaseMaterial(),m_rate(0.f){}
		TransparentMaterial(const vec3& color, float rate):BaseMaterial(color), m_rate(rate){}
		TransparentMaterial(BaseTexture* pTexture, float rate):BaseMaterial(pTexture), m_rate(rate){}
		virtual ~TransparentMaterial(){}

		virtual vec3 Shade(const vec3& wi, const vec3& ligColor, const Result& result)const override;
		virtual float Sample(const Result& result, const vec2& uv, vec3& wi)const override;

	private:
		float m_rate;
	};

}